﻿using DependencyInjection.StaticAccessor;
using FreeSql;
using FreeSql.Internal;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using System.Data.Common;
using System.Reflection;

namespace MultiTenant.FreeSql;

public static class FreeSqlCloudExtesions
{
    /// <summary>
    /// 获取原始Freesql
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="obj"></param>
    /// <returns></returns>
    public static IFreeSql? GetIFreeSql<T>(this T obj) where T : IBaseRepository
    {
        var s = obj.GetType().GetProperty("OrmOriginal", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(obj);
        if (s == null)
        {
            return obj.Orm;
        }
        return s as IFreeSql;
    }




    public static void ChangeDb(this IFreeSql fsql)
    {
        (fsql as FreeSqlCloud<string>)?.ChangeDb(TenantContext.Tenant);
    }


    /// <summary>
    /// 切换数据库
    /// </summary>
    /// <param name="fsql"></param>
    /// <param name="tenant"></param>
    public static void ChangeDb(this IFreeSql fsql, Tenant tenant)
    {
        (fsql as FreeSqlCloud<string>)?.ChangeDb(tenant);
    }

    public static void ChangeDb(this FreeSqlCloud<string> fsql, Tenant tenant)
    {
        if (tenant.Id <= 0) return;
        TenantContext.Tenant = tenant;
        ChangeDb(fsql, tenant.Db.DataType, tenant.Db.ConnectionString);
    }


    public static void ChangeDb(this FreeSqlCloud<string> fsql, DataType dataType, string constring)
    {
        //按数据库
        var dbkey = MD5Encrypt.Encrypt32(constring);

        // 只会首次注册，如果已经注册过则不生效
        fsql.Register(dbkey, () =>
        {
            var dbConfig = (PinnedScope.ScopedServices ?? throw new Exception("注入失败->113")).GetRequiredService<IOptionsMonitor<DbConfig>>();

            var db = new FreeSqlBuilder()
               .UseConnectionString(dataType, constring)
                .UseNameConvert(NameConvertType.PascalCaseToUnderscoreWithLower)//oracle 全部转为大写
               .CreateDatabaseIfNotExistsPgSql(dataType)

             // .UseAutoSyncStructure(env.IsDevelopment() || env.IsStaging())
             .UseMonitorCommand(
                 cmd =>
                 {
                     cmd.CommandTimeout = 9999;
                     if (dbConfig.CurrentValue.WatchCurd)
                     {
                         var p = "";
                         foreach (DbParameter item in cmd.Parameters)
                         {
                             if (p == "") p += "\r\nParameters：\r\n";
                             p += ($"ParameterName:{item.ParameterName},Value:{item.Value}\r\n");
                         }
                         Serilog.Log.Logger.Information("\r\n*******begin(" + (TenantContext.Tenant?.Identifier ?? "") + ")--TENANT--SQL================*********" + "\r\n" + cmd.CommandText + "\r\n" + p + "\r\n*******end================SQL================**********");
                     }
                 })
            .UseNoneCommandParameter(dbConfig.CurrentValue.NoneCommandParameter)//不使用命令参数化执行，针对 Insert/Update，也可临时使用 IInsert/IUpdate.NoneParameter()
            .Build();
            db.Aop.AuditValue += (s, e) =>
            {
                DbHelper.AuditValue(e);
            };

            db.Aop.ConfigEntityProperty += (s, e) =>
            {
                DbHelper.ConfigEntityProperty(s, e);
            };

            db.GlobalFilter.ApplyIf<ITenant>(nameof(ITenant), // 过滤器名称
               () => TenantContext.Tenant != null && TenantContext.Tenant.Id > 0, // 过滤器生效判断
                    a => a.TenantId == TenantContext.Tenant.Id // 过滤器条件
              , true);

            db.GlobalFilter.Apply<IBaseSoftDelete>(nameof(IBaseSoftDelete), a => a.IsDeleted == false);
            db.UseJsonMap();
            return db;
        });



        // 切换租户
        fsql.Change(dbkey);
    }

}
